﻿// License: The MIT License (MIT) Copyright (c) 2011..2012 Barend Gehrels

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Stormy;

namespace GrooveSharp
{
    public partial class ConfigurationFolders : UserControl
    {
        private const string ADDED_FOLDER = "<to be selected>";


        private class PathInfo : DependencyObject
        {
            #region PROPERTY REGISTRATION
            public static readonly DependencyProperty
                IdProperty = DependencyProperty.Register("Id",
                    typeof(int?), typeof(PathInfo),
                        new UIPropertyMetadata(null));

            public static readonly DependencyProperty
                PathProperty = DependencyProperty.Register("Path",
                    typeof(string), typeof(PathInfo),
                        new UIPropertyMetadata(null));

            public static readonly DependencyProperty
                ActiveProperty = DependencyProperty.Register("Active",
                    typeof(bool?), typeof(PathInfo),
                        new UIPropertyMetadata(null));

            public static readonly DependencyProperty
                EmptyProperty = DependencyProperty.Register("Empty",
                    typeof(bool), typeof(PathInfo),
                        new UIPropertyMetadata(null));
            #endregion

            private ConfigurationFolders m_editor;

            public PathInfo(ConfigurationFolders editor)
            {
                m_editor = editor;
            }

            public int Id
            {
                get { return (int)GetValue(IdProperty); }
                set { SetValue(IdProperty, value); }
            }

            public string Path
            {
                get { return (string)GetValue(PathProperty); }
                set { SetValue(PathProperty, value); }
            }

            public bool? Active
            {
                get { return (bool)GetValue(ActiveProperty); }
                set { SetValue(ActiveProperty, value); }
            }

            public bool Empty
            {
                get { return (bool)GetValue(EmptyProperty); }
                set { SetValue(EmptyProperty, value); }
            }

            public int Count { get; set; }

            protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
            {
                m_editor.m_commitNecessary = true;
                m_editor.textBlockDebug.Text = "True after Property Changed";
            }
        }

        private class PathInfoMapper : ISelectable<PathInfo>, IInsertable<PathInfo>, IUpdateable<PathInfo>, IAutoNumberable<PathInfo>, IDeleteable<PathInfo>
        {
            private ConfigurationFolders m_editor;

            public PathInfoMapper(ConfigurationFolders editor)
            {
                m_editor = editor;
            }

            public PathInfo ApplySelect(IDataReader reader)
            {
                int count = reader.AsInteger("count").Value;
                return new PathInfo(m_editor)
                {
                    Id = reader.AsInteger("path_id", 0),
                    Path = reader.AsString("path_folder"),
                    Active = reader.AsBool("is_active"),
                    Count = count,
                    Empty = count <= 0
                };
            }

            public string UpdateSql()
            {
                return "update paths set path_folder=@path,is_active=@active where path_id=@id";
            }

            public string InsertSql()
            {
                return "insert into paths(path_folder,is_active) values(@path,@active)";
            }

            public string DeleteSql()
            {
                return "delete from paths where path_id=@id";
            }


            private void Add_Path_And_Active(PathInfo item, IDbCommand command)
            {
                command.Parameters.Add(Db.CreateParameter(command, DbType.String, "@path", item.Path));
                command.Parameters.Add(Db.CreateParameter(command, DbType.Boolean, "@active", item.Active));
            }
            private void Add_Id(PathInfo item, IDbCommand command)
            {
                command.Parameters.Add(Db.CreateParameter(command, DbType.Int32, "@id", item.Id));
            }

            public void ApplyInsert(PathInfo item, IDbCommand command)
            {
                Add_Path_And_Active(item, command);
            }

            public void ApplyUpdate(PathInfo item, IDbCommand command)
            {
                Add_Id(item, command);
                Add_Path_And_Active(item, command);
            }

            public void ApplyAutoNumber(PathInfo item, int newId)
            {
                item.Id = newId;
            }

            public void ApplyDelete(PathInfo item, IDbCommand command)
            {
                Add_Id(item, command);
            }

        }


        private ObservableCollection<PathInfo> m_items;
        private ObservableCollection<PathInfo> m_deletedItems = new ObservableCollection<PathInfo>();
        private bool m_commitNecessary = false;

        private System.Windows.Forms.FolderBrowserDialog m_dialog = new System.Windows.Forms.FolderBrowserDialog();


        public ConfigurationFolders()
        {
            InitializeComponent();

            // Because there is only one ConfigurationEditor, we can register a mapper with a reference to this instance
            Orm.Register<PathInfo>(new PathInfoMapper(this));

#if DEBUG
            textBlockDebug.Visibility = Visibility.Visible;
#endif

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                Refresh();
            }
        }

        public void Refresh()
        {
            theListView.ItemsSource = null;

            m_items = new ObservableCollection<PathInfo>
                (
                    Db.Connection().Select<PathInfo>("select p.*,(select count(1) from tracks t where p.path_id=t.path_id) as count from paths p")
                );

            theListView.ItemsSource = m_items;
            m_items.CollectionChanged += delegate(object o, NotifyCollectionChangedEventArgs e)
            {
                m_commitNecessary = true;
                textBlockDebug.Text = "True after Collection Changed";

            };
            m_commitNecessary = false;
            textBlockDebug.Text = "False after Refresh";
        }

        private void buttonBrowsePath_Click(object sender, RoutedEventArgs e)
        {
            int id;
            if (sender is Button
                && ((sender as Button).Tag != null)
                && Int32.TryParse((sender as Button).Tag.ToString(), out id))
            {
                var selected = (from item in m_items where item.Id == id select item).First();

                if (selected.Path != ADDED_FOLDER)
                {
                    m_dialog.SelectedPath = selected.Path;
                }
                else if (m_dialog.SelectedPath == "")
                {
                    m_dialog.SelectedPath = Db.DefaultMusicPath();
                }
                System.Windows.Forms.DialogResult result = m_dialog.ShowDialog();

                if (result == System.Windows.Forms.DialogResult.OK
                    && selected.Path != m_dialog.SelectedPath)
                {
                    if (selected.Count > 0)
                    {
                        // Recursively check if new path contains MP3/M4A's? And if they are the same?
                        var answer = MessageBox.Show(String.Format("Note, there are {0} tracks associated in {1}, are you sure you want to move it to {2}?",
                                selected.Count, selected.Path, m_dialog.SelectedPath),
                                "Question", MessageBoxButton.YesNo, MessageBoxImage.Question);
                        if (answer != MessageBoxResult.Yes)
                        {
                            return;
                        }
                    }

                    selected.Path = m_dialog.SelectedPath;
                }
            }
        }

        private void buttonAdd_Click(object sender, RoutedEventArgs e)
        {
            m_items.Add(new PathInfo(this) 
                { 
                    Id = DbUtil.NewId(m_items, (i) => i.Id),
                    Path = ADDED_FOLDER,
                    Active = true,
                    Count = 0,
                    Empty = true
                });
        }

        private void buttonRemove_Click(object sender, RoutedEventArgs e)
        {
            if (theListView.SelectedItem != null && theListView.SelectedItem is PathInfo)
            {
                PathInfo item = theListView.SelectedItem as PathInfo;

                if (item.Id > 0)
                {
                    // Removing is only possible if there are no tracks related...
                    if (item.Count > 0)
                    {
                        MessageBox.Show(String.Format("Cannot remove {0}, there are {1} tracks associated", item.Path, item.Count),
                                "Error", MessageBoxButton.OK, MessageBoxImage.Error);

                        // We might make it inactive...

                        return;
                    }

                    m_deletedItems.Add(item);
                }

                m_items.Remove(item);
            }
        }

        private void buttonRefresh_Click(object sender, RoutedEventArgs e)
        {
            Refresh();
        }

        public bool CommitIfNecessary()
        {
            if (! m_commitNecessary)
            {
                return false;
            }

            Db.Connection().ApplyUpdates
                (
                    m_items
                    , m_deletedItems
                    , (p) => p.Id < 0 // insert these
                    , (p) => p.Id > 0 // update these (== everything, even unchanged)
                );

            m_commitNecessary = false;
            textBlockDebug.Text = "False after commit";

            return true;
        }

    }
}
